///////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001-2009.
// -------------------------------------------------------------------------
//  File name:   LMG_Parse.cpp
//  Version:     v1.00
//  Created:     07/10/2009 by Jaewon Jung
//  Description: Locomotion Group utility functions
// -------------------------------------------------------------------------
//
///////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "LMG.h"
#include <map>
#include <algorithm>
#include <functional>


namespace LMG
{
	bool ParseXML(CAnimationSet* pAnimationSet, GlobalAnimationHeaderLMG& rLMG)
	{
		uint32 numAnims = rLMG.m_arrBSAnimations.size();
		if (numAnims)
			return true; //already loaded

		const char* pathnameLMG = rLMG.GetFilePath(); 
		XmlNodeRef root		= g_pISystem->LoadXmlFromFile(pathnameLMG);	

		//g_pILog->LogToFile("Loading LMG %s", pathname);				// to file only so console is cleaner
		//g_pILog->UpdateLoadingScreen(0);
		if (root==0)
		{
			g_pILog->LogError ("locomotion-group not found: %s", pathnameLMG);
			return false;
		}

		const char* XMLTAG = root->getTag();

		if (strcmp(XMLTAG,"LocomotionGroup")==0) 
		{
			uint32 numPseudo=0;
			uint32 numExamples=0;
			uint32 numChilds = root->getChildCount();
			for (uint32 c=0; c<numChilds; c++)
			{
				XmlNodeRef nodeList = root->getChild(c);
				const char* ListTag = nodeList->getTag();

				//load example-list 
				if ( strcmp(ListTag,"ExampleList")==0 )
				{ 
					numExamples = nodeList->getChildCount();
					assert(numExamples);	
					if (numExamples>=MAX_LMG_ANIMS)
						CryFatalError("CryAnimation: too many examples in one LMG. Only 40 are allowed. Contact a programmer");
				}

				//load pseudo example-list 
				if ( strcmp(ListTag,"ExamplePseudo")==0 ) 
					numPseudo = nodeList->getChildCount();
			}
			//reserve real and pseudo parameters               
			rLMG.m_arrParameter.resize(numPseudo+numExamples);

			//----------------------------------------------------------------------

			for (uint32 c=0; c<numChilds; c++)
			{
				XmlNodeRef nodeList = root->getChild(c);
				const char* ListTag = nodeList->getTag();

				//-----------------------------------------------------------
				//---                load blending-type                   ---
				//-----------------------------------------------------------
				if (strcmp(ListTag,"BLENDTYPE")==0) 
				{
					uint32 sum = nodeList->haveAttr("type");
					assert(sum);
					if (sum)
					{
						const char *type = nodeList->getAttr("type");
						rLMG.m_nBlendCodeLMG = *(uint32*)type;
					}
					continue;
				}
				if (strcmp(ListTag,"CAPS")==0) 
				{
					uint32 sum = nodeList->haveAttr("code");
					assert(sum);
					if (sum)
					{
						const char *code = nodeList->getAttr("code");
						rLMG.m_nSelectionCapsCode = *(uint32*)code;
					}
					continue;
				}

				if (strcmp(ListTag,"THRESHOLD")==0) 
				{
					nodeList->getAttr( "tz",rLMG.m_fThreshold );
					continue;
				}
				if (strcmp(ListTag,"LMGPARAMS")==0) 
				{
					nodeList->getAttr( "LookAheadTime",rLMG.m_fDesiredLocalLocationLookaheadTime );
					continue;
				}


				//-----------------------------------------------------------
				//---  define dimensions of the LMG                       ---
				//-----------------------------------------------------------
				if ( strcmp(ListTag,"Dimensions")==0 ) 
				{
					uint32 num = nodeList->getChildCount();
					rLMG.m_Dimensions=num;

					if (num>0)
					{
						XmlNodeRef nodeExample = nodeList->getChild(0);
						const char* ExampleTag = nodeExample->getTag();
						if (strcmp(ExampleTag,"Param")==0) 
						{
							rLMG.m_strParaName0 = nodeExample->getAttr( "name" );
							nodeExample->getAttr( "min",rLMG.m_min0 );
							nodeExample->getAttr( "max",rLMG.m_max0 );
							nodeExample->getAttr( "scale",rLMG.m_scale0 );
							nodeExample->getAttr( "cells",rLMG.m_cells0 );	
							rLMG.m_min0*=rLMG.m_scale0;
							rLMG.m_max0*=rLMG.m_scale0;
							if (rLMG.m_cells0<3)
								rLMG.m_cells0=3;
						}
					}
					if (num>1)
					{
						XmlNodeRef nodeExample = nodeList->getChild(1);
						const char* ExampleTag = nodeExample->getTag();
						if (strcmp(ExampleTag,"Param")==0) 
						{
							rLMG.m_strParaName1 = nodeExample->getAttr( "name" );
							nodeExample->getAttr( "min",rLMG.m_min1 );
							nodeExample->getAttr( "max",rLMG.m_max1 );
							nodeExample->getAttr( "scale",rLMG.m_scale1 );
							nodeExample->getAttr( "cells",rLMG.m_cells1 );
							rLMG.m_min1*=rLMG.m_scale1;
							rLMG.m_max1*=rLMG.m_scale1;
							if (rLMG.m_cells1<3)
								rLMG.m_cells1=3;
						}
					}
					if (num>2)
					{
						XmlNodeRef nodeExample = nodeList->getChild(2);
						const char* ExampleTag = nodeExample->getTag();
						if (strcmp(ExampleTag,"Param")==0) 
						{
							rLMG.m_strParaName2 = nodeExample->getAttr( "name" );
							nodeExample->getAttr( "min",rLMG.m_min2 );
							nodeExample->getAttr( "max",rLMG.m_max2 );
							nodeExample->getAttr( "scale",rLMG.m_scale2 );
							nodeExample->getAttr( "cells",rLMG.m_cells2 );
							rLMG.m_min2*=rLMG.m_scale2;
							rLMG.m_max2*=rLMG.m_scale2;
							if (rLMG.m_cells2<3)
								rLMG.m_cells2=3;
						}
					}
					if (num>3)
					{
						XmlNodeRef nodeExample = nodeList->getChild(3);
						const char* ExampleTag = nodeExample->getTag();
						if (strcmp(ExampleTag,"Param")==0) 
						{
							rLMG.m_strParaName3 = nodeExample->getAttr( "name" );
							nodeExample->getAttr( "min",rLMG.m_min3 );
							nodeExample->getAttr( "max",rLMG.m_max3 );
							nodeExample->getAttr( "scale",rLMG.m_scale3 );
							nodeExample->getAttr( "cells",rLMG.m_cells3 );
							rLMG.m_min3*=rLMG.m_scale3;
							rLMG.m_max3*=rLMG.m_scale3;
							if (rLMG.m_cells3<3)
								rLMG.m_cells3=3;
						}
					}
					continue;
				}

				//-----------------------------------------------------------
				//load example-list 
				//-----------------------------------------------------------
				if ( strcmp(ListTag,"ExampleList")==0 ) 
				{
					uint32 num = nodeList->getChildCount();
					assert(num);
					rLMG.m_arrBSAnimations.reserve(num);
					for (uint32 i=0; i<num; i++) 
					{
						XmlNodeRef nodeExample = nodeList->getChild(i);
						const char* ExampleTag = nodeExample->getTag();
						if (strcmp(ExampleTag,"Example")==0) 
						{
							BSAnimationLMG bsa;
							nodeExample->getAttr( "Position",bsa.m_Position );

							bsa.m_animName.SetName(nodeExample->getAttr( "AName" ));

							const SCRCName &aName = bsa.m_animName;
							int32 id=pAnimationSet->GetAnimIDByCRC(aName.m_CRC32);
							if (id<0)
							{
								//name not found in animation-list (CAL-file error)
								const char* pDebugName = aName.GetName_DEBUG();
								AnimFileWarning(pAnimationSet->m_pModel->GetModelFilePath(),"locomotion group '%s' is invalid! The animation '%s' is not in the CAL-file.", pathnameLMG,pDebugName);
								return 0;
							}
							else
							{
								const ModelAnimationHeader* pAnim = pAnimationSet->GetModelAnimationHeader(id);
								assert(pAnim->m_nAssetType==CAF_File);
								int32 gaid=pAnim->m_nGlobalAnimId;
								GlobalAnimationHeaderCAF& rCAF = g_AnimationManager.m_arrGlobalCAF[gaid];
								if (rCAF.IsAssetNotFound())
								{
									AnimFileWarning(pAnimationSet->m_pModel->GetModelFilePath(),"locomotion group '%s' is invalid! The the asset for animation '%s' does not exist.", pathnameLMG,aName.GetName_DEBUG());
									return 0;
								}

								//---------------------------------------------------------------
								//---------------------------------------------------------------
								//---------------------------------------------------------------
								if (rLMG.m_Dimensions>0)
								{
									if (rLMG.m_strParaName0=="MoveSpeed")
									{
										rLMG.m_arrParameter[i].m_Para.x=rCAF.m_fMoveSpeed;
									}
									if (rLMG.m_strParaName0=="TurnAngle")
									{
										rLMG.m_arrParameter[i].m_Para.x=rCAF.m_fAssetTurn;
									}
									if (rLMG.m_strParaName0=="TurnSpeed")
									{
										bsa.m_qVelocity = Vec3(0,rCAF.m_fMoveSpeed,0);  //is this still needed?
										rLMG.m_arrParameter[i].m_Para.x=rCAF.m_fTurnSpeed;
									}
								}

								//---------------------------------------------------------------
								//---------------------------------------------------------------
								//---------------------------------------------------------------
								if (rLMG.m_Dimensions>1)
								{
									if (rLMG.m_strParaName1=="TurnSpeed")
									{
										bsa.m_qVelocity = Vec3(0,rCAF.m_fMoveSpeed,0);  //is this still needed?
										rLMG.m_arrParameter[i].m_Para.y=rCAF.m_fTurnSpeed*rLMG.m_scale1;
									}
									if (rLMG.m_strParaName1=="TravelAngle")
									{
										Vec3 vTravelVec  = (rCAF.m_EndLocation.t-rCAF.m_StartLocation.t).GetNormalizedSafe(Vec3(0,1,0));
										bsa.m_qVelocity = vTravelVec*rCAF.m_fMoveSpeed*rLMG.m_scale1; //is this still needed?
										f32 fTravelAngle = Ang3::CreateRadZ( Vec3(0,1,0),vTravelVec );
										rLMG.m_arrParameter[i].m_Para.y=fTravelAngle;
									}
									if (rLMG.m_strParaName1=="TravelSlope")
									{
										bsa.m_qVelocity = Vec3(0,rCAF.m_fMoveSpeed,0);  //is this still needed?
										rLMG.m_arrParameter[i].m_Para.y=rCAF.m_fSlope;
									}
								}

								//---------------------------------------------------------------
								//---------------------------------------------------------------
								//---------------------------------------------------------------

								if (rLMG.m_Dimensions>2)
								{
									if (rLMG.m_strParaName2=="TravelSlope")
									{
										bsa.m_qVelocity = Vec3(0,rCAF.m_fMoveSpeed,0);  //is this still needed?
										rLMG.m_arrParameter[i].m_Para.z=rCAF.m_fSlope;
									}
									if (rLMG.m_strParaName2=="TurnSpeed")
									{
										bsa.m_qVelocity = Vec3(0,rCAF.m_fMoveSpeed,0);  //is this still needed?
										rLMG.m_arrParameter[i].m_Para.z=rCAF.m_fTurnSpeed;
										if (fabsf(rLMG.m_arrParameter[i].m_Para.z)>0.77f)
											rLMG.m_arrParameter[i].m_Para.y=0;
									}
								}

								//---------------------------------------------------------------
								//---------------------------------------------------------------
								//---------------------------------------------------------------

								if (rLMG.m_Dimensions>3)
								{
									if (rLMG.m_strParaName3=="TravelSlope")
									{
										bsa.m_qVelocity = Vec3(0,rCAF.m_fMoveSpeed,0);  //is this still needed?
										rLMG.m_arrParameter[i].m_Para.w=rCAF.m_fSlope;
									}
								}

								nodeExample->getAttr( "SetPara0",rLMG.m_arrParameter[i].m_Para.x );
								nodeExample->getAttr( "SetPara1",rLMG.m_arrParameter[i].m_Para.y );
								nodeExample->getAttr( "SetPara2",rLMG.m_arrParameter[i].m_Para.z );
								nodeExample->getAttr( "SetPara3",rLMG.m_arrParameter[i].m_Para.w );
								rLMG.m_arrParameter[i].m_Para.x *= rLMG.m_scale0;
								rLMG.m_arrParameter[i].m_Para.y *= rLMG.m_scale1;
								rLMG.m_arrParameter[i].m_Para.z *= rLMG.m_scale2;
								rLMG.m_arrParameter[i].m_Para.w *= rLMG.m_scale3;

								rLMG.m_arrParameter[i].i0=i;
								rLMG.m_arrParameter[i].w0=1.0f;  //real examples always have a weight of 1.0f
								rLMG.m_arrParameter[i].i1=0;
								rLMG.m_arrParameter[i].w1=0.0f;
							}

							rLMG.m_arrBSAnimations.push_back(bsa);
						}
						else 
							return false;
					}
					continue;
				}


				//-----------------------------------------------------------
				//load pseudo example-list 
				//-----------------------------------------------------------
				if ( strcmp(ListTag,"ExamplePseudo")==0 ) 
				{
					uint32 num = nodeList->getChildCount();
					for (uint32 i=0; i<num; i++) 
					{
						XmlNodeRef nodeExample = nodeList->getChild(i);
						const char* ExampleTag = nodeExample->getTag();
						if (strcmp(ExampleTag,"Pseudo")==0) 
						{
							uint32 i0=-1; f32 w0=1.0f;
							uint32 i1=-1; f32 w1=1.0f;

							nodeExample->getAttr( "p0",i0 );
							assert(i0<numExamples);
							nodeExample->getAttr( "p1",i1 );
							assert(i1<numExamples);

							nodeExample->getAttr( "w0",w0 );
							nodeExample->getAttr( "w1",w1 );

							f32 sum=w0+w1;
							assert(fabsf(1.0f-sum)<0.00001f);

							rLMG.m_arrParameter[numExamples+i].m_Para=rLMG.m_arrParameter[i0].m_Para*w0 + rLMG.m_arrParameter[i1].m_Para*w1;
							Vec4 w4=rLMG.m_arrParameter[numExamples+i].m_Para;
							rLMG.m_arrParameter[numExamples+i].i0=i0;
							rLMG.m_arrParameter[numExamples+i].w0=w0;
							rLMG.m_arrParameter[numExamples+i].i1=i1;
							rLMG.m_arrParameter[numExamples+i].w1=w1;
						}
					}
					continue;
				}



				//-----------------------------------------------------------
				//---  load blend-annotation-list                          --
				//-----------------------------------------------------------
				if ( strcmp(ListTag,"Blendable")==0 ) 
				{
					uint32 num = nodeList->getChildCount();
					rLMG.m_arrBSAnnotations1.reserve(num);
					for (uint32 i=0; i<num; i++) 
					{
						XmlNodeRef nodeExample = nodeList->getChild(i);
						const char* ExampleTag = nodeExample->getTag();
						if (strcmp(ExampleTag,"Face")==0) 
						{
							BSBlendable face;
							uint32 res;
							res=nodeExample->getAttr( "p0",face.idx0 );
							if (res)
							{
								assert(face.idx0<(numExamples+numPseudo) );
								face.num++;
							}
							res=nodeExample->getAttr( "p1",face.idx1 );
							if (res)
							{
								assert(face.idx1<(numExamples+numPseudo) );
								face.num++;
							}

							res=nodeExample->getAttr( "p2",face.idx2 );
							if (res)
							{
								assert(face.idx2<(numExamples+numPseudo) );
								face.num++;
							}

							res=nodeExample->getAttr( "p3",face.idx3 );
							if (res)
							{
								assert(face.idx3<(numExamples+numPseudo) );
								face.num++;
							}
							res=nodeExample->getAttr( "p4",face.idx4 );
							if (res)
							{
								assert(face.idx4<(numExamples+numPseudo) );
								face.num++;
							}
							res=nodeExample->getAttr( "p5",face.idx5 );
							if (res)
							{
								assert(face.idx5<(numExamples+numPseudo) );
								face.num++;
							}
							res=nodeExample->getAttr( "p6",face.idx6 );
							if (res)
							{
								assert(face.idx6<(numExamples+numPseudo) );
								face.num++;
							}
							res=nodeExample->getAttr( "p7",face.idx7 );
							if (res)
							{
								assert(face.idx7<(numExamples+numPseudo) );
								face.num++;
							}

							rLMG.m_arrBSAnnotations1.push_back(face);
						}
					}
					continue;
				}


				//-----------------------------------------------------------
				//---  load blend-annotation-list                          --
				//-----------------------------------------------------------
				if ( strcmp(ListTag,"VGrid")==0 ) 
				{
					uint32 numVExamples = nodeList->getChildCount();
					uint32 nGridSize = rLMG.m_cells0*rLMG.m_cells1*rLMG.m_cells2;
					if (numVExamples!=nGridSize)
						continue;

					rLMG.m_ParaGrid3D_1.resize(numVExamples);
					for (uint32 i=0; i<numVExamples; i++) 
					{
						XmlNodeRef nodeExample = nodeList->getChild(i);
						const char* ExampleTag = nodeExample->getTag();
						if (strcmp(ExampleTag,"VExample")==0) 
						{
							uint32 res;
							res=nodeExample->getAttr( "i0",rLMG.m_ParaGrid3D_1[i].i0);
							res=nodeExample->getAttr( "i1",rLMG.m_ParaGrid3D_1[i].i1);
							res=nodeExample->getAttr( "i2",rLMG.m_ParaGrid3D_1[i].i2);
							res=nodeExample->getAttr( "i3",rLMG.m_ParaGrid3D_1[i].i3);
							res=nodeExample->getAttr( "i4",rLMG.m_ParaGrid3D_1[i].i4);
							res=nodeExample->getAttr( "i5",rLMG.m_ParaGrid3D_1[i].i5);
							res=nodeExample->getAttr( "i6",rLMG.m_ParaGrid3D_1[i].i6);
							res=nodeExample->getAttr( "i7",rLMG.m_ParaGrid3D_1[i].i7);

							res=nodeExample->getAttr( "w0",rLMG.m_ParaGrid3D_1[i].w0);
							res=nodeExample->getAttr( "w1",rLMG.m_ParaGrid3D_1[i].w1);
							res=nodeExample->getAttr( "w2",rLMG.m_ParaGrid3D_1[i].w2);
							res=nodeExample->getAttr( "w3",rLMG.m_ParaGrid3D_1[i].w3);
							res=nodeExample->getAttr( "w4",rLMG.m_ParaGrid3D_1[i].w4);
							res=nodeExample->getAttr( "w5",rLMG.m_ParaGrid3D_1[i].w5);
							res=nodeExample->getAttr( "w6",rLMG.m_ParaGrid3D_1[i].w6);
							res=nodeExample->getAttr( "w7",rLMG.m_ParaGrid3D_1[i].w7);
						}
					}
					continue;
				}


				//-----------------------------------------------------------
				//---  load blend-annotation-list                          --
				//-----------------------------------------------------------
				if ( strcmp(ListTag,"Blendable2")==0 ) 
				{
					uint32 num = nodeList->getChildCount();
					rLMG.m_arrBSAnnotations2.reserve(num);
					for (uint32 i=0; i<num; i++) 
					{
						XmlNodeRef nodeExample = nodeList->getChild(i);
						const char* ExampleTag = nodeExample->getTag();
						if (strcmp(ExampleTag,"Face")==0) 
						{
							BSBlendable face;
							uint32 res;
							res=nodeExample->getAttr( "p0",face.idx0 );
							if (res)
							{
								assert(face.idx0<(numExamples+numPseudo) );
								face.num++;
							}
							res=nodeExample->getAttr( "p1",face.idx1 );
							if (res)
							{
								assert(face.idx1<(numExamples+numPseudo) );
								face.num++;
							}

							res=nodeExample->getAttr( "p2",face.idx2 );
							if (res)
							{
								assert(face.idx2<(numExamples+numPseudo) );
								face.num++;
							}

							res=nodeExample->getAttr( "p3",face.idx3 );
							if (res)
							{
								assert(face.idx3<(numExamples+numPseudo) );
								face.num++;
							}
							res=nodeExample->getAttr( "p4",face.idx4 );
							if (res)
							{
								assert(face.idx4<(numExamples+numPseudo) );
								face.num++;
							}
							res=nodeExample->getAttr( "p5",face.idx5 );
							if (res)
							{
								assert(face.idx5<(numExamples+numPseudo) );
								face.num++;
							}
							res=nodeExample->getAttr( "p6",face.idx6 );
							if (res)
							{
								assert(face.idx6<(numExamples+numPseudo) );
								face.num++;
							}
							res=nodeExample->getAttr( "p7",face.idx7 );
							if (res)
							{
								assert(face.idx7<(numExamples+numPseudo) );
								face.num++;
							}

							rLMG.m_arrBSAnnotations2.push_back(face);
						}
					}
					continue;
				}

				//-----------------------------------------------------------
				//---  load blend-annotation-list                          --
				//-----------------------------------------------------------
				if ( strcmp(ListTag,"VGrid2")==0 ) 
				{
					uint32 numVExamples = nodeList->getChildCount();
					uint32 nGridSize = rLMG.m_cells0*rLMG.m_cells1*rLMG.m_cells3;
					if (numVExamples!=nGridSize)
						continue;

					rLMG.m_ParaGrid3D_2.resize(numVExamples);
					for (uint32 i=0; i<numVExamples; i++) 
					{
						XmlNodeRef nodeExample = nodeList->getChild(i);
						const char* ExampleTag = nodeExample->getTag();
						if (strcmp(ExampleTag,"VExample")==0) 
						{
							uint32 res;
							res=nodeExample->getAttr( "i0",rLMG.m_ParaGrid3D_2[i].i0);
							res=nodeExample->getAttr( "i1",rLMG.m_ParaGrid3D_2[i].i1);
							res=nodeExample->getAttr( "i2",rLMG.m_ParaGrid3D_2[i].i2);
							res=nodeExample->getAttr( "i3",rLMG.m_ParaGrid3D_2[i].i3);
							res=nodeExample->getAttr( "i4",rLMG.m_ParaGrid3D_2[i].i4);
							res=nodeExample->getAttr( "i5",rLMG.m_ParaGrid3D_2[i].i5);
							res=nodeExample->getAttr( "i6",rLMG.m_ParaGrid3D_2[i].i6);
							res=nodeExample->getAttr( "i7",rLMG.m_ParaGrid3D_2[i].i7);

							res=nodeExample->getAttr( "w0",rLMG.m_ParaGrid3D_2[i].w0);
							res=nodeExample->getAttr( "w1",rLMG.m_ParaGrid3D_2[i].w1);
							res=nodeExample->getAttr( "w2",rLMG.m_ParaGrid3D_2[i].w2);
							res=nodeExample->getAttr( "w3",rLMG.m_ParaGrid3D_2[i].w3);
							res=nodeExample->getAttr( "w4",rLMG.m_ParaGrid3D_2[i].w4);
							res=nodeExample->getAttr( "w5",rLMG.m_ParaGrid3D_2[i].w5);
							res=nodeExample->getAttr( "w6",rLMG.m_ParaGrid3D_2[i].w6);
							res=nodeExample->getAttr( "w7",rLMG.m_ParaGrid3D_2[i].w7);
						}
					}
					continue;
				}


				//-----------------------------------------------------------
				//-- check of Motion-Combination examples 
				//-----------------------------------------------------------
				if ( strcmp(ListTag,"MotionCombination")==0 ) 
				{
					uint32 num = nodeList->getChildCount();
					rLMG.m_strSpliceAnim.resize(num);
					for (uint32 i=0; i<num; i++) 
					{
						XmlNodeRef nodeExample = nodeList->getChild(i);
						const char* ExampleTag = nodeExample->getTag();

						if (strcmp(ExampleTag,"NewStyle")==0) 
						{
							rLMG.m_strSpliceAnim[i].SetName(nodeExample->getAttr( "Style" ));
						}
						else
						{
							assert(0); //illegal Tag found
							return 0;
						}
					}
					continue;
				}

				//-----------------------------------------------------------
				//-- joint mask
				//-----------------------------------------------------------
				if (strcmp(ListTag, "JointList") == 0)
				{
					uint32 num = nodeList->getChildCount();
					rLMG.m_jointList.resize(num);
					for (uint32 i=0; i<num; ++i)
					{
						XmlNodeRef node = nodeList->getChild(i);
						const char* tag = node->getTag();
						if (strcmp(tag, "Joint") != 0)
						{
							assert(0);
							return 0;
						}

						const char* name = node->getAttr("Name");
						rLMG.m_jointList[i] = g_pCrc32Gen->GetCRC32(name);
					}

					std::sort(rLMG.m_jointList.begin(), rLMG.m_jointList.end());
					continue;
				}
			}
			assert(rLMG.m_nBlendCodeLMG);
		}

		return true;
	}
} // namespace LMG
